﻿/*
 *   ConvertionFunctions.cs
 *   Copyright (c) 2011 - BitFox Software and Ricardo Federico Villafañes
 *   Contact: federvillaf@hotmail.com
 *   
 *   Licensing: This product is covered by Microsoft Reciprocal License (MS-RL)
 *              see https://bitfoxeval.codeplex.com/license
*/

using System;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.CodeAnalysis;

namespace BitFox.Evaluator.Functions
{
    /// <summary>
    /// Built-in conversion functions for the evaluator.
    /// </summary>
    public static class ConvertionFunctions
    {
        /// <summary>
        /// Converts a string to a numeric type.
        /// </summary>
        /// <param name="src">The string to be parsed</param>
        /// <returns>
        /// The type of the return is 'object' because the concrete type could be any of the integer types, and the decimal type.
        /// Any way. this function choose the shorter type that is able to fully store the parsed string.
        /// </returns>
        public static object Val(string src)
        {
            if (src == null) throw new ArgumentNullException("src");
            long res = 0, sign = 1;
            int step = 0;
            bool isdec = false;
            decimal decres = 0, divisor = 1;
            foreach(char ch in (string)src)
            {
                if (char.IsWhiteSpace(ch))
                {
                    if (step != 0) break;
                }
                else if (ch == '-')
                {
                    if (step != 0) break;
                    sign = -1;
                    step = 1;
                }
                else if (ch == '.')
                {
                    if (isdec) break;
                    isdec = true;
                    decres = (decimal)(res * sign);
                    step = 1;
                }
                else
                {
                    step = 1;
                    if (char.IsDigit(ch))
                    {
                        if(isdec)
                        {
                            divisor *= 10;
                            decres = decres + (((byte)ch) - '0') / divisor;
                        }
                        else
                            res = res * 10 + ((byte)ch) - '0';
                    }
                    else
                        break;
                }
            }

            if (isdec) return decres;
            res *= sign;
            if (res >= byte.MinValue && res <= byte.MaxValue) return (byte)res;
            if (res >= short.MinValue && res <= short.MaxValue) return (short)res;
            if(res >= int.MinValue && res <= int.MaxValue) return (int)res;
            return res;
        }


        /// <summary>
        /// Helper method for 'Soundex' function
        /// </summary>
        /// <param name="ch">The character to be phonetized</param>
        /// <returns>The phonetic code of character, or char.MinValue if character doesn't have a phonetic representation, or
        /// '9' if <b>ch</b> is not an alphabetic char.
        /// </returns>
        static char SoundexHelper(char ch)
        {
            switch (ch)
            {
                case 'B':   case 'F':   case 'P':   case 'V':
                    return '1';

                case 'C':   case 'G':   case 'J':   case 'K':
                case 'Q':   case 'S':   case 'X':   case 'Z':
                    return '2';

                case 'D':   case 'T':
                    return '3';

                case 'L':
                    return '4';

                case 'M':   case 'N':
                    return '5';

                case 'R':
                    return '6';

                case 'A':   case 'E':   case 'H':   case 'I':
                case 'O':   case 'U':   case 'W':   case 'Y':
                    return char.MinValue;
            }

            return '9';
        }

        /// <summary>
        /// Returns a phonetic representation of a given string.
        /// </summary>
        /// <param name="src">The string to be phonetized</param>
        /// <returns>four characters representing the phonetics of passed string.</returns>
        static public string Soundex(string src)
        {
            src = src.FoxToUpper();
            if (src.Length <= 0) return "0000";
            StringBuilder res = new StringBuilder();
            res.Append(src[0]);

            // Process the string.
            char lastChar = char.MinValue;
            for (int index = 1; index < src.Length; index++)
            {
                char code = SoundexHelper(src[index]);
                if (code != '9')
                {
                    if (lastChar != code && code != char.MinValue)
                    {
                        res.Append(code);
                        if (res.Length == 4) break;
                    }
                    lastChar = code;
                }
            }

            // Complete 4 digits
            while (res.Length < 4) res.Append('0');
            return res.ToString();
        }

        /// <summary>
        /// Not implemented
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Usage", "CA1801")]
        static public string AnsiToOem(string str)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not implemented
        /// </summary>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Usage", "CA1801")]
        static public string OemToAnsi(string str)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not implemented
        /// </summary>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Usage", "CA1801")]
        static public string Transform(object target, string format)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not implemented
        /// </summary>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Usage", "CA1801")]
        static public string Type(object target)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not implemented
        /// </summary>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Usage", "CA1801")]
        static public string CPConvert(int codePage1, int codePage2, string target)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not implemented
        /// </summary>
        /// <returns></returns>
        static public string CPCurrent()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Not implemented
        /// </summary>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Usage", "CA1801")]
        static public string CPCurrent(int actual)
        {
            throw new NotImplementedException();
        }
    }
}
